
package biblio.util;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import org.apache.log4j.Logger;


/**
 * 
 * Class is helpful by using its method as for example universal toString method
 * @author GM Mephisto
 * @since 2011-04-09
 */
public class AuxClass
{
    /**
     * Class prints informations to log file if log level is set to INFO
     * @param o an instance of class which will be described as result
     * @param foreseenCapacity the capacity which is reserver for string of characters
     * @return string which describes an instance given by x
     */
    public static String toString(Object o, int foreseenCapacity)
    {
        Class<?> cl = o.getClass();
        StringBuffer desc = new StringBuffer(cl.getName());
        desc.ensureCapacity(foreseenCapacity);
        
        //check fields of the class and its all parent classes
        do
        {
            desc.append("[");
            Field[] fields = cl.getDeclaredFields();
            AccessibleObject.setAccessible(fields, true);

            //getting names and values all fields
            for (int i = 0,length=fields.length; i < length; i++)
            {
                Field p = fields[i];
                desc.append(p.getName());
                desc.append("=");

                try
                {
                    Object obj = p.get(o);

                    if (obj == null)
                        desc.append("null");
                    else
                        desc.append(obj.toString());
                }
                catch (Exception ex)
                {
                    logger.error(ex);
                }

                if (i < length - 1)
                    desc.append(",");
            }
            desc.append("]");
            cl = cl.getSuperclass();
         }
         while (cl != Object.class);
         logger.info("name="+cl.getName()+", length="+desc.length()+", capacity="+desc.capacity());
        
         return desc.toString();
    }

    public static final boolean isSerializationAndReflectionAttackPossible (String className)
    {
         try
         {
            Constructor<?> c1 = Class.forName(className).getDeclaredConstructors()[0];
            c1.setAccessible(true);
            Class<?> cl = (Class<?>) c1.newInstance(0);
         }
         catch (ClassNotFoundException ex)
         {
        	 logger.error(ex);
             return false;
         }
         catch (InstantiationException ex)
         {
        	 logger.error(ex);
             return false;
         }
         catch (IllegalAccessException ex)
         {
        	 logger.error(ex);
             return false;
         }
         catch (IllegalArgumentException ex)
         {
        	 logger.error(ex);
             return false;
         }
         catch (InvocationTargetException ex)
         {
             logger.error(ex);
             return false;
         }

        return true;
    }

    /**
     * Checks if arg is false. If it is false throws an exception {@code e} given by a reference.
     *
     * @param arg the arg to test
     * @param e the runtime exception to throw if arg is false
     */
    public static void checkArgument(boolean flag, RuntimeException e) throws RuntimeException
    {
    	if (!flag)
            throw e;
    }
    
    /**
     * Checks if arg is null. If it is null throws an exception {@code e} given by a reference.  
     * 
     * @param arg the arg to test if it is null
     * @param e the runtime exception to throw if arg is null
     */
    public static void checkArgument(Object arg, RuntimeException e) throws RuntimeException
    {
    	if (arg == null)
            throw e;
    }
    
    /**
     * Checks if arg is null. If it is null throws an exception {@code e} given by a reference.  
     * 
     * @param arg the arg to test if it is null
     * @param e the Throwable exception to throw if arg is null
     */
    public static void checkArgument(Object arg, Throwable e) throws Throwable
    {
    	if (arg == null)
            throw e;
    }

    /**
     * Checks if arg is false. If it is false throws an exception {@code e} given by a reference.
     *
     * @param arg the arg to test
     * @param e the runtime exception to throw if arg is false
     */
    public static void checkArgument(boolean flag, Throwable e) throws Throwable
    {
    	if (!flag)
            throw e;
    }

    /**
     * Makes a deep copy of this object. It uses serialization to create a copy.
     *
     * @param o an object to clone
     * @return the deep copy of Object.
     *
     * @throws IOException if an I/O error occurs while writing stream header
     * @throws ClassNotFoundException if Class of a serialized object cannot be found.
     */
    public static Object clone(Object o) throws IOException, ClassNotFoundException
    {
        ObjectOutputStream oos = null;
        try
        {
            //write object to bytes array
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(o);
            oos.close();
            //build clone from bytes array
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Object res = ois.readObject();
            ois.close();
            return res;
        }
        finally
        {
            try
            {
                oos.close();
            }
            catch (IOException ex)
            {
                System.out.println(ex);
                logger.error(ex);
            }
        }
    }
    
    
    //private static Logger logger = Logger.getLogger("LOG");
    private static Logger logger = Logger.getLogger(AuxClass.class);
}
